package qr.server.admin;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import javax.swing.DefaultListModel;
import javax.swing.JFrame;

import qr.core.Game;
import qr.core.Location;

/**
 * Administration GUI.
 * 
 * @author Brian
 *
 */
@SuppressWarnings("serial")
public class ApplicationWindow extends JFrame {
	
	/**
	 * Screen lookup table.
	 */
	private Map<String, Class<? extends ApplicationScreen>> states;
	



	/**
	 * Creates an application table with a reference to a state transition table.
	 */
	public ApplicationWindow() {
		super();
		
		this.states = new HashMap<String, Class<? extends ApplicationScreen>>();
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(640, 480);
		this.setTitle("QR Game Administration Console");
	}

	/**
	 * Shows the desired screen as the content pane.
	 * 
	 * Screen is found via lookup in {@link ApplicationWindow#states}.
	 * 
	 * @param target Name of screen to show
	 * @return this
	 */
	public ApplicationWindow render(String target, Object[] objs) {
		if (!this.states.containsKey(target))
			throw new RuntimeException("Screen [" + target + "] was not found in state table.");
		
		ApplicationScreen screen;
		try {
			screen = this.states.get(target).getConstructor(ApplicationWindow.class, Object[].class).newInstance(this, objs);
			this.setContentPane(screen);
		} catch (Exception e) {
			System.err.println("Couldn't construct the target screen.");
			e.printStackTrace();
		}		
		this.validate();
		this.repaint();
		
		return this;
	}
	
	/**
	 * Shows the desired screen as the content pane.
	 * 
	 * Screen is found via lookup in {@link ApplicationWindow#states}.
	 * 
	 * @param target Name of screen to show
	 * @return this
	 */
	public ApplicationWindow render(String target) {
		if (!this.states.containsKey(target))
			throw new RuntimeException("Screen [" + target + "] was not found in state table.");
		
		ApplicationScreen screen;
		try {
			screen = this.states.get(target).getConstructor(ApplicationWindow.class).newInstance(this);
			this.setContentPane(screen);
		} catch (Exception e) {
			System.err.println("Couldn't construct the target screen.");
			e.printStackTrace();
		}		
		this.validate();
		this.repaint();
		
		return this;
	}
	
	/**
	 * Shows the frame.
	 * 
	 * @return this
	 */
	public ApplicationWindow start() {
		this.setVisible(true);
		
		return this;
	}
	
	/**
	 * Loads a screen and shows the frame.
	 * 
	 * @param screen Name of screen to show when first started
	 * @return this
	 */
	public ApplicationWindow start(String screen) {
		this.render(screen);
		this.start();
		
		return this;
	}

	/**
	 * Adds given states to the state table.
	 * 
	 * @param states States to add
	 * @return this
	 */
	@SuppressWarnings("unchecked")
	public ApplicationWindow include(Class<? extends ApplicationScreen>... states) {
		for (Class<? extends ApplicationScreen> clazz : states)
			this.states.put(clazz.getSimpleName(), clazz);
		
		return this;
	}
	
	/**
	 * Loads a single application screen into the state table given its class.
	 * 
	 * This method hides the nastiness of reflection away.
	 * 
	 * @param clazz class to add to the state table
	 */
/*	private void bootstrap(Class<? extends ApplicationScreen> clazz) {
		try {
			// Retrieve the constructor
			Constructor<? extends ApplicationScreen> constructor =
					clazz.getDeclaredConstructor(ApplicationWindow.class);
			
			// Create the screen
			ApplicationScreen screen = constructor.newInstance(this);
			
			// Get screen name
			String name = clazz.getSimpleName();
			
			// Add screen to states table
			this.states.put(name, screen);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}*/
}
